package com.uminho.http;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.Iterator;

import org.apache.http.client.ClientProtocolException;
import org.apache.http.message.BasicNameValuePair;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.content.Context;
import android.util.Log;

import com.uminho.exceptions.DestroyException;
import com.uminho.exceptions.InvalidJSonException;
import com.uminho.exceptions.InvalidOAuthParametersError;
import com.uminho.exceptions.InvalidOAuthTokenError;
import com.uminho.exceptions.NotAllowedError;
import com.uminho.exceptions.OAuthServiceFailureError;
import com.uminho.exceptions.RecurrentAppointmentsException;
import com.uminho.exceptions.SaveException;
import com.uminho.exceptions.userOverlappedAppointmentsException;
import com.uminho.objects.AppClient;
import com.uminho.objects.Appointment;
import com.uminho.objects.AppointmentNotification;
import com.uminho.objects.Bookmark;
import com.uminho.objects.Notification;
import com.uminho.objects.Resource;
import com.uminho.objects.Service;
import com.uminho.objects.SimpleAppointment;
import com.uminho.objects.SimpleService;
import com.uminho.objects.Slot;
import com.uminho.objects.Task;
import com.uminho.objects.User;
import com.uminho.objects.UserSettings;
import com.uminho.objects.exchangeNotification;


/****c* http/Webservice
* DESCRIPTION
* Class intermediária entre a aplicação mobile e o servidor do egend.me. Toda a comunicação deverá utilizar esta class que comunica com os webservices e utiliza como outputs objetos java.
****
*/
public class Webservice {

	/* <Zona Singleton> */
	private static Webservice instance;

	private Webservice() {
		try {
			token = InternalStorage.openToken();
		} catch (Exception e) {
			token = "";
		}
		formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
		formatter.setTimeZone(java.util.TimeZone.getTimeZone("UTC"));
	}

	/****f* Webservice/getInstance
	* DESCRIPTION 
	* Construtor da class Webservice. É um singleton para manter as informações de autenticação do utilizador sincronizadas e atualizadas.
	* RESULT 
	* Retorna um objeto WebService
	* EXAMPLE
	Webservice ser = Webservice.getInstance();
	****
	*/
	public static Webservice getInstance() {
		if (instance == null)
			instance = new Webservice();
		return instance;
	}
 
	/* </Zona Singleton> */
	String token;
	SimpleDateFormat formatter;
	// // DOMINIO EGEND.ME

	public static String domain = "http://egend.me";
	private static String oauth_consumer_key = "89a5mzjsldjh3e2ghne9n2bm4";
	private static String oauth_consumer_secret = "39n6e6900it80lg5msaxqp91m";

	//public static String domain = "http://192.168.100.196:3000";
    //public static String oauth_consumer_key = "3ak9xmgo0i70z6bq4ppdbkxek";
    //public static String oauth_consumer_secret = "2ma32wo4jil6h4waa22uc2rkb";
//	
	// // IP Rui
//	String domain = "http://192.168.100.181:3000";
//	String oauth_consumer_key = "7edzkf76nm4amg3uquxl5lcvy";
//	String oauth_consumer_secret = "b6i9xkihw4hnkcm0z1rrxlhg0";
	
//	 IP do André
//	 public static String domain = "http://192.168.100.204:3000";
//	 public static String oauth_consumer_key = "27kg29pt696rk5gqks7j9f0f";
//	 public static String oauth_consumer_secret = "191w4rldlgr1s86wpae3xpydf";

	/****f* Webservice/jsonProfile
	* DESCRIPTION 
	* Método privado utilizado por outros métodos que durante a troca de informações com o webservice recebam informações de perfil.
	* INPUTS
	* Recebe um objeto JSONObject que representa um perfil.
	* RESULT 
	* Retorna uma objeto java do tipo User.
	* EXAMPLE
	JSONObject profile = json.getJSONObject("Profile");
	User u = jsonProfile(profile);
	****
	*/
	private User jsonProfile(JSONObject profile) throws InvalidJSonException,
			NumberFormatException, JSONException, ParseException,
			MalformedURLException, IOException {
		Long id;
		String username, name, email, phone, mobile_phone, address, website, birthday;
		Character gender;
		
		
		name = getJsonString(profile, "name");
		username = getJsonString(profile.getJSONObject("user"), "username");
		email = getJsonString(profile.getJSONObject("user"), "email");
		id = getJsonLong(profile.getJSONObject("user"), "id");
		phone = getJsonString(profile, "phone");
		mobile_phone = getJsonString(profile, "mobile_phone");
		address = getJsonString(profile, "address");
		website = getJsonString(profile, "website");
		birthday = getJsonString(profile, "birthdate");
		String gendertemp = getJsonString(profile, "gender");
		if (gendertemp.length() != 0) {
			gender = gendertemp.charAt(0);
		} else {
			gender = null;
		}

		User u = new User(id, username, name, email, phone, mobile_phone,
				website, gender, address);
		// yyyy-MM-dd
		if (!birthday.equals(""))
			u.setBirthday(birthday);
		u.setAvatar();
		return u;
	}
	
	/****f* Webservice/jsonSettings
	* DESCRIPTION 
	* Método privado utilizado por outros métodos que durante a troca de informações com o webservice recebam informações das definições.
	* INPUTS
	* Recebe um objeto JSONObject que representa as definições.
	* RESULT 
	* Retorna uma objeto java do tipo UserSettings.
	* EXAMPLE
	JSONObject settings = json.getJSONObject("Settings");
	UserSettings u = jsonSettings(settings);
	****
	*/
	private UserSettings jsonSettings(JSONObject settings) throws InvalidJSonException,
			NumberFormatException, JSONException, ParseException,
			MalformedURLException, IOException {
		String app_scheduled, app_confirmed, app_queued, app_delayed, app_canceled, app_reminder, app_failed, review_reminder, recurrent_appointment_finish;

		app_scheduled = getJsonString(settings,"app_scheduled");
		app_confirmed = getJsonString(settings,"app_confirmed");
		app_queued = getJsonString(settings,"app_queued");
		app_delayed = getJsonString(settings,"app_delayed");
		app_canceled = getJsonString(settings,"app_canceled");
		app_reminder = getJsonString(settings,"app_reminder");
		app_failed = getJsonString(settings,"app_failed");
		review_reminder = getJsonString(settings,"review_reminder");
		recurrent_appointment_finish = getJsonString(settings,"recurrent_appointment_finish");
	

		UserSettings u = new UserSettings(valueOf(app_scheduled), valueOf(app_confirmed), valueOf(app_queued), valueOf(app_delayed), 
				valueOf(app_canceled), valueOf(app_reminder), valueOf(app_failed), valueOf(review_reminder), valueOf(recurrent_appointment_finish));
		
		return u;
	}

	private boolean toBoolean(String s) {
	    return ((s != null) && s.equalsIgnoreCase("true"));
	}

	private Boolean valueOf(String s) {
	    return (toBoolean(s)? Boolean.TRUE : Boolean.FALSE);
	}

	
	/****f* Webservice/getProfile
	* DESCRIPTION 
	* Método que comunica com o webservice para buscar a informação do utilizador que está autenticado.
	* RESULT 
	* Retorna um objeto User que contém as várias informações associadas ao utilizador autenticado. 
	* EXAMPLE
	Webservice w = Webservice.getInstance();
	User u = w.getProfile();
	****
	*/
	public User getProfile() throws NumberFormatException,
			MalformedURLException, InvalidJSonException, ParseException,
			IOException, InvalidOAuthParametersError, InvalidOAuthTokenError,
			OAuthServiceFailureError, NotAllowedError, URISyntaxException,
			JSONException, SaveException, DestroyException {

		JSONObject json = conectToServer("/api/profile","GET");

		try {
			JSONObject profile = json.getJSONObject("profile");
			User u = jsonProfile(profile);
			return u;
		} catch (JSONException e) {
			if (json != null) {
				throwExceptionHandler(json);
			}
		}
		return null;
	}

	/****f* Webservice/getSettings
	* DESCRIPTION 
	* Método para buscar as definições do utilizador
	* RESULT 
	* Retorna um objeto settings, com as várias definições 
	* EXAMPLE
	Webservice w = Webservice.getInstance();
	UserSettings u = w.getSettings();
	****
	*/
	public UserSettings getSettings() throws NumberFormatException,
			MalformedURLException, InvalidJSonException, ParseException,
			IOException, InvalidOAuthParametersError, InvalidOAuthTokenError,
			OAuthServiceFailureError, NotAllowedError, URISyntaxException,
			JSONException, SaveException, DestroyException {

		JSONObject json = conectToServer("/api/settings","GET");
		try {
			JSONObject settings = json.getJSONObject("UserSettings");
			UserSettings u = jsonSettings(settings);
			return u;
		} catch (JSONException e) {
			if (json != null) {
				throwExceptionHandler(json);
			}
		}
		return null;
	}
	
	/****f* Webservice/setSettings
	* DESCRIPTION 
	* Define novas definições do utilizador
	* INPUT
	* Todos as variáveis (app_scheduled, app_confirmed, app_queued, app_delayed, app_canceled, app_reminder, app_failed, review_reminder, recurrent_appointment_finish) que constituem o objeto UserSettings
	* RESULT 
	* Retorna verdadeiro caso a ação seja bem sucedido; caso contrário falso. 
	* EXAMPLE
	Webservice w = Webservice.getInstance();
	if w.setSettings(app_scheduled, app_confirmed, app_queued, app_delayed, app_canceled, app_reminder, app_failed, review_reminder, recurrent_appointment_finish)
		continue();
	****
	*/
	public Boolean setSettings(Boolean app_scheduled, Boolean app_confirmed,
			Boolean app_queued, Boolean app_delayed, Boolean app_canceled,
			Boolean app_reminder, Boolean app_failed, Boolean review_reminder,
			Boolean recurrent_appointment_finish) throws ClientProtocolException, IOException, InvalidOAuthParametersError, InvalidOAuthTokenError, OAuthServiceFailureError, NotAllowedError, JSONException, SaveException, DestroyException  {
		JSONObject json = null;
		ArrayList<BasicNameValuePair> postParameters = new ArrayList<BasicNameValuePair>();
		String url = getDomain() + "/api/settings";
		postParameters.add(new BasicNameValuePair("app_scheduled", app_scheduled.toString()));
		postParameters.add(new BasicNameValuePair("app_confirmed", app_confirmed.toString()));
		postParameters.add(new BasicNameValuePair("app_queued", app_queued.toString()));
		postParameters.add(new BasicNameValuePair("app_delayed", app_delayed.toString()));
		postParameters.add(new BasicNameValuePair("app_canceled", app_canceled.toString()));
		postParameters.add(new BasicNameValuePair("app_reminder", app_reminder.toString()));
		postParameters.add(new BasicNameValuePair("app_failed", app_failed.toString()));
		postParameters.add(new BasicNameValuePair("review_reminder", review_reminder.toString()));
		postParameters.add(new BasicNameValuePair("recurrent_appointment_finish", recurrent_appointment_finish.toString()));
		String jsonString = Http.executeHttpPut(url, postParameters,this.token);

		try {
			json = new JSONObject(jsonString);
		} catch (JSONException e2) {
			Log.e("Egend.me-Exception", e2.getMessage());
		}
		if (json != null) {
			try {
				if ((json.getString("status")).equals("success")) {
					return true;
				}
			} catch (Exception e) {
				throwExceptionHandler(json);
			}
		}
		return false;
	}
	
	/****f* Webservice/throwExceptionHandler
	* DESCRIPTION 
	* Método utilizado pela maioria dos métodos que comunicam com o webservice. Uma vez que o Webservice retorna na maioria dos casos um pequeno grupo de exceções, este método controla-as.
	* O método deve ser utilizado sempre que o Webservice pode retornar uma lista de exceções. Nesses casos, este método deve ser retornado caso o Json retornado pelo webservice não seja o previsto.
	* INPUTS
	* Objeto JSONObject que o servidor envia aquando de algum pedido. 
	* RESULT 
	* É enviada uma excepção (das várias possíveis). No caso de ser alguma excepção não prevista, é enviada um JSONexcpetion.
	* EXAMPLE
	try {
			profile = json.getJSONObject("Profile");
		} catch (JSONException e) {
			throwExceptionHandler(json);
		}
	****
	*/
	private void throwExceptionHandler(JSONObject json)
			throws InvalidOAuthParametersError, InvalidOAuthTokenError,
			OAuthServiceFailureError, NotAllowedError, JSONException,
			SaveException, DestroyException {
		int i;
		String s = "";
		JSONArray exceptionsList;
		JSONObject exception;
		
		try{
			exceptionsList = json.getJSONArray("Errors");
			for (i = 0; i < exceptionsList.length(); i++) {
				exception = exceptionsList.getJSONObject(i);
				Log.d("ERRORS",exception.toString());
			}
		}catch (Exception e) {}
		try{
			exceptionsList = json.getJSONArray("ExceptionsList");
		}catch (Exception e) {
			throw new JSONException("Unknown Error on Exception Handling");
		}
		for (i = 0; i < exceptionsList.length();) {
			try {
				exception = exceptionsList.getJSONObject(i);
				Log.e("Egend.me-Exception", exception.getString("message"));
				s = exception.getString("type");
			} catch (JSONException e) {
				Log.e("Egend.me-Exception",
						"Unknown Error on Exception Handling");
			}
			if (s.equals("InvalidOAuthParametersError")) {
				throw new InvalidOAuthParametersError();
			} else if (s.equals("InvalidOAuthTokenError")) {
				throw new InvalidOAuthTokenError();
			} else if (s.equals("OAuthServiceFailureError")) {
				throw new OAuthServiceFailureError();
			} else if (s.equals("NotAllowedError")) {
				throw new NotAllowedError();
			} else if (s.equals("SaveException")) {
				throw new SaveException();
			} else if (s.equals("DestroyException")) {
				throw new DestroyException();
			} else if (s.equals("client_secret")) {
				throw new DestroyException();
			} else {
				throw new JSONException("Unknown Error on Exception Handling");
			}
		}

	}

	/****f* Webservice/jsonService
	* DESCRIPTION 
	* Método privado utilizado por outros métodos que durante a troca de informações com o webservice recebam informações de Serviços.
	* INPUTS
	* Objeto JSONObject que contenha informação de um Serviço.
	* RESULT 
	* Objeto Service.
	* EXAMPLE
	Service service = json.getJSONObject("Service");
	JSONObject s = jsonService(service);
	****
	*/
	private Service jsonService(JSONObject service) {
		Long id;
		Integer rating, category_id;
		JSONObject provider;
		String username, name, email, phone, mobile_phone, address, website, birthday, description, vatin;
		ArrayList<Resource> resourceArray = new ArrayList<Resource>();
		ArrayList<Task> tasksArray = new ArrayList<Task>();
		ArrayList<AppClient> clientsArray = new ArrayList<AppClient>();

		id = getJsonLong(service, "id");
		name = getJsonString(service, "name");
		description = getJsonString(service, "description");
		vatin = getJsonString(service, "vatin");
		try {
			provider = service.getJSONObject("provider");
		} catch (Exception e) {
			provider = null;
		}
		if (provider != null) {
			email = getJsonString(provider, "email");
			username = getJsonString(provider, "username");
		} else {
			email = username = "";
		}
		rating = getJsonInteger(service, "rating");
		category_id = getJsonInteger(service, "category_id");
		try {
			JSONObject profile = service.getJSONObject("profile");
			phone = getJsonString(profile, "phone");
			mobile_phone = getJsonString(profile, "mobile_phone");
			address = getJsonString(profile, "address");
			website = getJsonString(profile, "website");
			birthday = getJsonString(profile, "birthdate");
		} catch (Exception e) {
			phone = mobile_phone = address = website = birthday = "";
		}

		// *************** ResourcesList
		try {
			JSONArray ResourcesList = service.getJSONArray("resources");
			resourceArray = getResources(ResourcesList);
		} catch (Exception e) {
		}

		// *************** TasksList
		try {
			JSONArray tasksList = service.getJSONArray("tasks");
			tasksArray = getTasks(tasksList);
		} catch (Exception e) {
		}

		// *************** ClientsList
		try {
			JSONArray clientsList = service.getJSONArray("end_users");
			clientsArray = getClients(clientsList);
		} catch (Exception e) {
		}

		Service s = new Service(id, username, name, email, phone, mobile_phone,
				website, address, description, vatin, resourceArray,
				tasksArray, clientsArray, rating, category_id);

		try {
			if (!birthday.equals(""))
				s.setBirthday(birthday);
		} catch (Exception e) {
			Log.d("Serviço", "Erro ao definir o AVATAR");
		}
		try {
			s.setAvatar();
		} catch (Exception e) {
			Log.d("Serviço", "Erro ao definir o AVATAR");
		}
		return s;
	}

	/****f* Webservice/getService
	* DESCRIPTION 
	* Método para buscar um determinado Service ao servidor.
	* INPUTS
	* O identificador (o id do tipo long) do serviço.
	* RESULT 
	* É retornado um objeto Service que contém as informações do serviço pedido.
	* EXAMPLE
	Webservice w = Webservice.getInstance();
	Service s = w.getService(312365);
	****
	*/
	public Service getService(Long id) throws NumberFormatException,
			MalformedURLException, InvalidJSonException, ParseException,
			IOException, InvalidOAuthParametersError, InvalidOAuthTokenError,
			OAuthServiceFailureError, NotAllowedError, URISyntaxException,
			JSONException, SaveException, DestroyException {

		Service s = new Service();
		JSONObject service;

		JSONObject json = conectToServer("/api/services/" + id.toString(),"GET");
		try {
			service = json.getJSONObject("service");
			Log.d("Servico", service.toString());
			s = jsonService(service);
		} catch (JSONException e) {
			if (json != null) {
				throwExceptionHandler(json);
			}
		}
		return s;
	}

	
	/****f* Webservice/getAppointmentByID
	* DESCRIPTION 
	* Método para buscar um determinado Appointment ao servidor.
	* INPUTS
	* O identificador (o id do tipo long) do appointment.
	* RESULT 
	* É retornado um objeto Appointment que contém as informações do serviço pedido.
	* EXAMPLE
	Webservice w = Webservice.getInstance();
	Appointment s = w.getAppointmentByID(312365);
	****
	*/
	public Appointment getAppointmentByID(Long id) throws NumberFormatException,
			MalformedURLException, InvalidJSonException, ParseException,
			IOException, InvalidOAuthParametersError, InvalidOAuthTokenError,
			OAuthServiceFailureError, NotAllowedError, URISyntaxException,
			JSONException, SaveException, DestroyException {

		JSONObject json = conectToServer("/api/appointments/" + id.toString(),"GET");

		try {
			JSONObject service = json.getJSONObject("appointment");
			Appointment s = createAppointment(service);
			return s;
		} catch (JSONException e) {
			if (json != null) {
				throwExceptionHandler(json);
			}
		}
		return null;
	}
	/****f* Webservice/getSlotByServiceByDay
	* DESCRIPTION 
	* Método que retorna todas as slts de um serviço num determinado dia. Retorna as slots vazias (que possivelmente serão ocupadas) e as ocupadas.
	* INPUTS
	* O identificador (o id do tipo long) do serviço e um dia (através de um GregorianCalendar)
	* RESULT 
	* Retorna uma lista de objetos Slot.
	* EXAMPLE
	Webservice w = Webservice.getInstance();
	GregorianCalendar cal = new GregorianCalendar();
	Long id = 312365;
	ArrayList<Slot> array = w.getSlotByServiceByDay(id,cal);
	****
	*/
	public ArrayList<Slot> getSlotByServiceByDay(Long id, GregorianCalendar cal)
			throws ClientProtocolException, URISyntaxException, IOException,
			InvalidOAuthParametersError, InvalidOAuthTokenError,
			OAuthServiceFailureError, NotAllowedError, JSONException,
			SaveException, DestroyException {
		ArrayList<Slot> array = new ArrayList<Slot>();
		JSONObject slot;
		int i;
		JSONArray slotList;
		Slot s;

		String year = String.valueOf(cal.get(GregorianCalendar.YEAR));
		String month = String.valueOf(cal.get(GregorianCalendar.MONTH)+1);
		String day = String.valueOf(cal.get(GregorianCalendar.DAY_OF_MONTH));
		String parcialURL = "/api/services/" + id + "/slots?day=" + day
				+ "&month=" + month + "&year=" + year;

		JSONObject json = conectToServer(parcialURL,"GET");
		
		if (json != null) {
			if (statusSuccess(json)) {
				try {
					slotList = json.getJSONArray("availabilities");
					for (i = 0; i < slotList.length(); i++) {
						s = null;
						try {
							slot = slotList.getJSONObject(i);
							s = createSlot(slot);
							if (s != null)
								array.add(s);
						} catch (JSONException e) {
							Log.e("Egend.me-Exception",
									"Unknown Error on getSlotByServiceByDay");
						}
					}
				} catch (JSONException e1) {
					return array;
				}
			} else {
				throwExceptionHandler(json);
			}
		}
		return array;
	}

	/****f* Webservice/createSlot
	* DESCRIPTION 
	* Método privado utilizado por outros métodos que durante a troca de informações com o webservice recebam informações de slots de tempo.
	* INPUTS
	* Um objeto JSONObject que representa uma slot temporal.
	* RESULT 
	* Um objeto SLOT com as várias informações associadas.
	* EXAMPLE
	slotList = json.getJSONArray("Slots");
	for (i = 0; i < slotList.length(); i++) {
		slot = slotList.getJSONObject(i);
		s = createSlot(slot);
		array.add(s);
	}
	****
	*/
	private Slot createSlot(JSONObject slot) {
		Long appID;
		GregorianCalendar begDate, endDate;

		begDate = getJsonDate(slot, "begin");
		endDate = getJsonDate(slot, "end");
		appID = getJsonLong(slot, "appointment_id");
		if (endDate==null && begDate!=null)
			endDate = new GregorianCalendar(begDate.get(GregorianCalendar.YEAR),
											begDate.get(GregorianCalendar.MONTH),
											begDate.get(GregorianCalendar.DAY_OF_MONTH),
											23,59,59);
		if (endDate==null || begDate==null)
			return null;
		return new Slot(begDate, endDate, appID);
	}

	/****f* Webservice/SearchService
	* DESCRIPTION 
	* Método utilizado para pesquisas por serviços. Este método recebe vários argumentos o que significa que através dele é possível realmente pesquisas avançadas.
	* INPUTS
	* Página (para poder haver paginaçaão); nome OU tag; categoria; latitude e longitude. Quando algum campo estiver vazio, deve ser enviado um null!
	* Direction pode ser null ou "asc" ou "desc"
	* Sort pode ser null ou "rating" ou "name"
	* RESULT 
	* Lista de serviços (com informação parcial, não completa dos serviços, semelhante a SimpleService)
	* EXAMPLE
	Webservice w = Webservice.getInstance();
	ArrayList<SimpleService> array = w.SearchService("1","Cabeleireiro Manuel Silva",null,null,null,null,null,null);
	ArrayList<SimpleService> array2 = w.SearchService("1",null, "extensões","Cabeleireiro",null,null);
	****
	*/
	public ArrayList<Service> SearchService(String page, String nome,
			String tag, String categoria, String longitude, String latitude,
			String morada, String direction, String sort) throws ClientProtocolException, URISyntaxException,
			IOException, InvalidOAuthParametersError, InvalidOAuthTokenError,
			OAuthServiceFailureError, NotAllowedError, JSONException,
			SaveException, DestroyException {
		ArrayList<Service> array = new ArrayList<Service>();
		ArrayList<Long> partnerArray = new ArrayList<Long>();
		JSONObject service,partnersList;
		JSONArray servicesList;
		Boolean success = false, added = false;
		Iterator iter;
		Service s;
		Long key;
		int j;

		ArrayList<BasicNameValuePair> postParameters = new ArrayList<BasicNameValuePair>();

		if (page != null)
			addParam(postParameters, "page", page);
		if (sort != null)
			addParam(postParameters, "sort", sort);
		if (direction != null)
			addParam(postParameters, "direction", direction);
		if (nome != null) {
			addParam(postParameters, "name", nome);
		} else {
			if (tag != null) {
				addParam(postParameters, "tag", tag);
			}
		}
		if (categoria != null) {
			addParam(postParameters, "category", categoria);
		}
		if (morada != null) {
			addParam(postParameters, "address", morada);
		} else {
			if (longitude != null && latitude != null) {
				addParam(postParameters, "longitude", longitude);
				addParam(postParameters, "latitude", latitude);
			}
		}

		JSONObject json = conectToServer("/api/services/search","POST",postParameters);

		try {
			success = json.getString("status").equals("success");
		} catch (JSONException e) {
		}

		if (json != null) {
			if (success) {
				try {
					servicesList = json.getJSONArray("service");
				} catch (JSONException e1) {
					return array;
				}
				try {
					partnersList = json.getJSONObject("sp");
				} catch (JSONException e1) {
					partnersList = null;
				}
				if (partnersList != null){
					iter = partnersList.keys();
				    while(iter.hasNext()){
				        key = (Long)iter.next();
				        partnerArray.add(key);
				    }
				}
				
				if (servicesList.length() == 0)
					return array;
				if (servicesList != null) {
					for (int i = 0; i < servicesList.length(); i++) {
						s = null;
						try {
							service = servicesList.getJSONObject(i);
						} catch (JSONException e) {
							Log.e("Egend.me-Exception",
									"Unknown Error on SearchService");
							service = null;
						}
						if (service != null)
							s = jsonService(service);
						if (s != null)
							added = false;
							for(j=0; j<partnerArray.size();j++){
								if (partnerArray.get(j)==s.getId()){
									array.add(1, s);
									s.setIsPartner(true);
									added = true;
								}
							}
							if (!added)
								array.add(s);
					}
				}
			} else {
				if (!success) {
					throwExceptionHandler(json);
				}
			}
		}
		
		return array;
	}

	/****f* Webservice/createSimpleService
	* DESCRIPTION 
	* Método privado utilizado por outros métodos que durante a troca de informações com o webservice recebam informações de serviços (serviços com informação parcial, diretamente relacionados com os objetos Simple Service)
	* INPUTS
	* Um objeto JSONObject que representa um serviço com informação parcial
	* RESULT 
	* Um objeto SimpleService com a informação obtida pela leitura do JSON
	* EXAMPLE
	servicesList = json.getJSONArray("Services");
	for (int i = 0; i < servicesList.length(); i++) {
		service = servicesList.getJSONObject(i);
		s = createSimpleService(service);
		array.add(s)
	}
	****
	*/
	private SimpleService createSimpleService(JSONObject service) {
		Long category_id;
		String title, description, id;

		id = getJsonString(service, "service_id");
		title = getJsonString(service, "title");
		description = getJsonString(service, "description");
		category_id = getJsonLong(service, "category_id");

		SimpleService s = new SimpleService(id, title, description,category_id);
		try {
			s.setAvatar();
		} catch (Exception e) {
		}
		return s;
	}

	/****f* Webservice/getBookmarks
	* DESCRIPTION 
	* Método para buscar os vários favoritos do utilizador que está autenticado no momento. 
	* RESULT 
	* Lista de objetos Bookmark
	* EXAMPLE
	Webservice w = Webservice.getInstance();
	ArrayList<Bookmark> array = w.getBookmarks();
	****
	*/
	public ArrayList<Bookmark> getBookmarks() throws ClientProtocolException,
			URISyntaxException, IOException, InvalidOAuthParametersError,
			InvalidOAuthTokenError, OAuthServiceFailureError, NotAllowedError,
			JSONException, SaveException, DestroyException {
		ArrayList<Bookmark> array = new ArrayList<Bookmark>();
		JSONObject service;
		JSONArray servicesList = null;
		SimpleService s;
		Bookmark b;

		JSONObject json = conectToServer("/api/bookmarks","GET");
		
		if (statusSuccess(json)){
			try {
				servicesList = json.getJSONArray("bookmarks");
			} catch (JSONException e1) {
				Log.e("getBookmarks-ArrayException", e1.getMessage());
				return array;
			}
			if (servicesList.length()==0)
				return array;
			for (int i = 0; i < servicesList.length(); i++) {
				s = b = null;
				try {
					service = servicesList.getJSONObject(i);
					if (service != null) {
						s = createSimpleService(service);
						b = new Bookmark(service.getLong("bookmark_id"), s);
					}
					if (b != null)
						array.add(b);
				} catch (JSONException e) {
					Log.e("getBookmarks-Exception",
							"Unknown Error on getBookmarks adding element to array");
				}
			}
		} else {
			throwExceptionHandler(json);
			return array;
		}
		return array;
	}

	/****f* Webservice/getNotifications
	* DESCRIPTION 
	* Método que transfere todas as notificações por ler do utilizador autenticado.
	* RESULT 
	* Lista de objetos Notification, que representam as várias notificações. 
	* EXAMPLE
		Webservice ws = Webservice.getInstance();
		ArrayList<com.uminho.objects.Notification> notifications = ws.getNotifications();
	****
	*/
	public ArrayList<Notification> getNotifications()
			throws ClientProtocolException, URISyntaxException, IOException,
			InvalidOAuthParametersError, InvalidOAuthTokenError,
			OAuthServiceFailureError, NotAllowedError, JSONException,
			SaveException, DestroyException {
		ArrayList<Notification> array = new ArrayList<Notification>();
		JSONObject notification;
		JSONArray notificationsList;
		Notification n;
		
		JSONObject json = conectToServer("/api/notifications","GET");
		if (statusSuccess(json)) {
			try {
				notificationsList = json.getJSONArray("notification");
				if (notificationsList != null) {
					for (int i = 0; i < notificationsList.length(); i++) {
						n = null;
						try {
							notification = notificationsList.getJSONObject(i);
							if (notification != null)
								n = createNotification(notification);
							if (n != null)
								array.add(n);
						} catch (JSONException e) {
							Log.e("Egend.me-Exception","Unknown Error on getNotifications");
						}
					}
				}
			} catch (JSONException e1) {
				return array;
			}
		} else {
			throwExceptionHandler(json);
		}
		return array;
	}

	/****f* Webservice/createNotification
	* DESCRIPTION 
	* Método privado utilizado por outros métodos que durante a troca de informações com o webservice recebam informações de Notificações
	* INPUTS
	* Recebe um JSONObject que informação de uma notificação
	* RESULT 
	* Retorna um objeto Notification com as váris informações obtidas do objeto JSON. 
	* EXAMPLE
	JSONObject notification = notificationsList.getJSONObject(i);
	Notification n = createNotification(notification);
	****
	*/
	private Notification createNotification(JSONObject notification) {
		String id, type;
		try {
			id = getJsonString(notification, "id");
			type = getJsonString(notification, "notification_type");
			if (type.startsWith("appointment") || type.startsWith("recurrent_") || type.equals("time_available") || type.equals("client_late")) {
				Appointment a = createAppointment(notification.getJSONObject("appointment"));
				AppointmentNotification n = new AppointmentNotification(id,type, a);
				if (type.startsWith("appointment_canceled") || type.startsWith("recurrent_appointment_canceled")) {
					n.getAppointment().setCanceled();
				}
				return n;
			} 
			else if (type.startsWith("exchange")) {
				JSONObject req_app = notification.getJSONObject("requester_appointment");
				JSONObject serv = notification.getJSONObject("service");
				SimpleAppointment requester_appointment = createSimpleAppointment(req_app, serv);
				
				Appointment a = createAppointment(notification.getJSONObject("appointment"));
				
				Long exchangeID = getJsonLong(notification, "exchange_id");

				exchangeNotification n = new exchangeNotification(id, type, a, requester_appointment, exchangeID);
				return n;
			}
			
			Notification n = new Notification(id, type);
			return n;
		} catch (Exception e) {
			Log.e("Egend.me-SlotException", "Exception on createNotification:"
					+ e.getMessage());
			return null;
		}
	}

	private SimpleAppointment createSimpleAppointment(JSONObject app, JSONObject serv){
			Long category_id;
			GregorianCalendar beg, end;
			String comment, title, description, id;;
			
			Long appointmentID = getJsonLong(app, "id");
			beg = getJsonDate(app, "begin");
			end = getJsonDate(app, "end");
			comment = getJsonString(app, "comment");
			
			id = getJsonString(serv, "id");
			title = getJsonString(serv, "name");
			description = getJsonString(serv, "description");
			category_id = getJsonLong(serv, "category_id");
			

			SimpleService s = new SimpleService(id, title, description, category_id);
			try {
				s.setAvatar();
			} catch (Exception e) {
			}
			
			SimpleAppointment appointment = new SimpleAppointment(s, appointmentID, beg, end, comment); 
			return appointment;
	}

	/****f* Webservice/login
	* DESCRIPTION 
	* Método que faz a autenticação de um utilizador.
	* INPUTS
	* Recebe o username e a password para a autenticação. Ainda recebe o Context da aplicação para que o token da autenticação seja guardado corretamente na aplicação.
	* RESULT 
	* É guardado o token (Xauth), que permite a comunicação com o servidor, na aplicação e é retornado um booleano que representa o sucesso ou insucesso da operação.
	* EXAMPLE
		Webservice w = Webservice.getInstance();
		if (w.login(username, password, this))
			nextView();
	****
	*/
	public Boolean login(String user, String pass, Context c) throws Exception {
		ArrayList<BasicNameValuePair> postParameters = new ArrayList<BasicNameValuePair>();
		String token = "";

		postParameters.add(new BasicNameValuePair("oauth_consumer_key",
				getOauth_consumer_key()));
		postParameters.add(new BasicNameValuePair("oauth_consumer_secret",
				getOauth_consumer_secret()));
		postParameters.add(new BasicNameValuePair("x_auth_username", user));
		postParameters.add(new BasicNameValuePair("x_auth_password", pass));
		
		JSONObject json = conectToServer("/oauth/xauthorize","POST",postParameters);
		if (json != null) {
			try {
				if ((json.getString("status")).equals("success")) {
					token = json.getString("access_token");
				}
			} catch (Exception e) {
				throwExceptionHandler(json);
			}
		}

		if (!(InternalStorage.saveToken(token)))
			token = "";
		else
			this.token = token;

		if (this.token.equals(""))
			return false;
		else
			return true;
	}

	/****f* Webservice/Registo
	* DESCRIPTION 
	* Método que regista um novo utilizador (do tipo cliente) no servidor. Em caso de sucesso o login é feito automaticamente, atualizando/criando o novo token.
	* INPUTS
	* Recebe um nome de utilizador, uma password e um email. Para além disso, para guardar o token na aplicação, ainda necessita da Context da aplicação. 
	* RESULT 
	* Em caso de insucesso é retornada uma lista de erros, que diz em que campos houve a falha (por exemplo, email repetido ou username repetido);
	* Em caso de sucesso, um novo token é guardado na aplicação (efeito equivalente ao método Login); é retornada uma lista com um elemento, apresentando o sucesso da operação.
	* EXAMPLE
	Webservice w = Webservice.getInstance();
	ArrayList<String> array = w.registo(username, password, email, this)
	for(String s: array){
				if (s.equals("success"){
					break;
					nextView();
				}else{
				NotifyError(s);
			}
	****
	*/
	public String Registo(String user, String pass, String email,
			Context c) throws Exception {
		Boolean errors = false;
		String token = "";
		ArrayList<BasicNameValuePair> postParameters = new ArrayList<BasicNameValuePair>();

		postParameters.add(new BasicNameValuePair("username", user));
		postParameters.add(new BasicNameValuePair("password", pass));
		postParameters.add(new BasicNameValuePair("email", email));
		postParameters.add(new BasicNameValuePair("client_id",
				getOauth_consumer_key()));
		postParameters.add(new BasicNameValuePair("client_secret",
				getOauth_consumer_secret()));

		JSONObject json = conectToServer("/api/registrations","POST",postParameters);
		if (json != null) {
			try {
				if ((json.getString("status")).equals("success")) {
					token = json.getString("access_token");
				}
			} catch (Exception e) {
				errors = true;
			}
			if (!errors) {
				if (InternalStorage.saveToken(token)){
					this.token = token;
					return "success";
				}
			} else {
				try {
					JSONArray errorsArray = json.getJSONArray("Errors");
					for (int i = 0; i < errorsArray.length(); i++) {
						try{
							return errorsArray.getJSONObject(i).getString("email");
						}catch (Exception e) {
						}
						try{
							return errorsArray.getJSONObject(i).getString("username");
						}catch (Exception e) {
						}
					}

				} catch (Exception e) {
					throwExceptionHandler(json);
				}
			}
		}

		return "Error";
	}
	
	/****f* Webservice/setProfile
	* DESCRIPTION 
	* Método que atualiza o perfil do utilizador autenticado
	* INPUTS
	* Recebe um nome do utilizador, email, numero de telefone, numero de telemovel, género,  data de nascimento e website.
	* RESULT 
	* Em caso de insucesso é retornada "false";
	* Em caso de sucesso é retornada "true";
	* EXAMPLE
	Webservice w = Webservice.getInstance();
	if (w.setProfile(utilizador, email, telefone, telemovel, genero,  data_de_nascimento, website))
		continue();
	else
		throw exception()
	****
	*/
	public Boolean setProfile(String name, String email, String username, String phone, String mobile_phone, String gender, String birthdate, String website, String address,
			Context c) throws ClientProtocolException, IOException, InvalidOAuthParametersError, InvalidOAuthTokenError, OAuthServiceFailureError, NotAllowedError, JSONException, SaveException, DestroyException, URISyntaxException {
		ArrayList<BasicNameValuePair> postParameters = new ArrayList<BasicNameValuePair>();

		postParameters.add(new BasicNameValuePair("name", name));
		postParameters.add(new BasicNameValuePair("username", username));
		postParameters.add(new BasicNameValuePair("email", email));
		postParameters.add(new BasicNameValuePair("phone", phone));
		postParameters.add(new BasicNameValuePair("mobile_phone", mobile_phone));
		postParameters.add(new BasicNameValuePair("gender", gender));
		postParameters.add(new BasicNameValuePair("address", address));
		postParameters.add(new BasicNameValuePair("birthdate", birthdate));
		postParameters.add(new BasicNameValuePair("website", website));

		JSONObject json = conectToServer("/api/profile","PUT",postParameters);
		if (json != null) {
			try {
				if ((json.getString("status")).equals("success")) {
					return true;
				}
			} catch (Exception e) {
				throwExceptionHandler(json);
			}
		}
		return false;
	}

	/****f* Webservice/getAgenda
	* DESCRIPTION 
	* Retorna uma agenda de compromissos do utilizador autenticado. Esta agenda é uma lista de dias em que cada dia tem uma lista de compromissos.
	* RESULT 
	* É retornada uma lista de listas de compromissos. Ou seja, uma lista de dias (que contenham compromissos); cada dia é uma lista que contém um ou mais compromissos. No caso de o utilizador não ter nenhum compromisso marcado, é retornada uma lista de listas vazia.
	* EXAMPLE
	Webservice ws = Webservice.getInstance();
	ArrayList<ArrayList<Appointment>> array = ws.getAgenda()
	for (ArrayList<Appointment> a : array){
		print(a.get(0).startDate();
		for (Appointment p : a){
			printAppointment(p);
			}
		}
	****
	*/
	public ArrayList<ArrayList<Appointment>> getAgenda()
			throws ClientProtocolException, URISyntaxException, IOException,
			InvalidOAuthParametersError, InvalidOAuthTokenError,
			OAuthServiceFailureError, NotAllowedError, JSONException,
			SaveException, DestroyException {
		ArrayList<ArrayList<Appointment>> array = new ArrayList<ArrayList<Appointment>>();
		ArrayList<Appointment> temp;
		JSONObject appointment;
		JSONArray appointmentsList, daysList;
		Appointment s;

		JSONObject json = conectToServer("/api/agenda","GET");
		if (statusSuccess(json)) {
			try {
				daysList = json.getJSONArray("appointments");
			} catch (JSONException e1) {
				return array;
			}
			if (daysList != null) {
				try {
					for (int i = 0; i < daysList.length(); i++) {
						appointmentsList = daysList.getJSONArray(i);
						temp = new ArrayList<Appointment>();
						if (appointmentsList != null) {
							for (int j = 0; j < appointmentsList.length(); j++) {
								s = null;
								try {
									appointment = appointmentsList.getJSONObject(j);
								} catch (JSONException e) {
									Log.e("Egend.me-Exception",
											"Unknown Error on Agenda");
									appointment = null;
								}
								if (appointment != null){
									
									s = createAgendaAppointment(appointment);
									if (s != null)
										temp.add(s);
								}
							}
							array.add(temp);
						}
					}
				} catch (JSONException e1) {
					return array;
				}
			}
		}else{
			throwExceptionHandler(json);
		}
		return array;
	}

	
	/****f* Webservice/getAgendaPro
	* DESCRIPTION 
	* Retorna uma agenda de compromissos de um serviço por ressource ou por task  . Esta agenda é uma lista de dias em que cada dia tem uma lista de compromissos.
	* RESULT 
	* É retornada uma lista de listas de compromissos. Ou seja, uma lista de dias (que contenham compromissos); cada dia é uma lista que contém um ou mais compromissos. No caso de o utilizador não ter nenhum compromisso marcado, é retornada uma lista de listas vazia.
	****
	*/
	public ArrayList<ArrayList<Appointment>> getAgendaPro(Long serviceID, Long taskID, Long resourceID)
			throws ClientProtocolException, URISyntaxException, IOException,
			InvalidOAuthParametersError, InvalidOAuthTokenError,
			OAuthServiceFailureError, NotAllowedError, JSONException,
			SaveException, DestroyException {
		ArrayList<ArrayList<Appointment>> array = new ArrayList<ArrayList<Appointment>>();
		ArrayList<Appointment> temp;
		JSONObject appointment;
		JSONArray appointmentsList, daysList;
		Appointment s;

		ArrayList<BasicNameValuePair> postParameters = new ArrayList<BasicNameValuePair>();
		if (resourceID!=null)
			addParam(postParameters, "resource_id", resourceID);
		if (taskID!=null)
			addParam(postParameters, "task_id", taskID);
		JSONObject json = conectToServer("/agenda/show_to_collaborator","GET",postParameters);
		if (statusSuccess(json)) {
			try {
				daysList = json.getJSONArray("appointments");
			} catch (JSONException e1) {
				return array;
			}
			if (daysList != null) {
				try {
					for (int i = 0; i < daysList.length(); i++) {
						appointmentsList = daysList.getJSONArray(i);
						temp = new ArrayList<Appointment>();
						if (appointmentsList != null) {
							for (int j = 0; j < appointmentsList.length(); j++) {
								s = null;
								try {
									appointment = appointmentsList.getJSONObject(j);
								} catch (JSONException e) {
									Log.e("Egend.me-Exception",
											"Unknown Error on Agenda");
									appointment = null;
								}
								if (appointment != null){
									
									s = createAgendaAppointment(appointment);
									if (s != null)
										temp.add(s);
								}
							}
							array.add(temp);
						}
					}
				} catch (JSONException e1) {
					return array;
				}
			}
		}else{
			throwExceptionHandler(json);
		}
		return array;
	}
	
	/****f* Webservice/GetAppointments
	* DESCRIPTION 
	* Retorna uma lista de compromissos consoante um conjunto de parâmetros e associados ao utilizador autenticado. É particularmente importante para preencher os compromissos por meses, em que um dos parâmetros é o mês a ser pedido.
	* INPUTS
	* Parâmetros a serem pedidos ao servidor
	* RESULT 
	* Uma lista de compromissos conforme os parâmetros pedidos.
	* EXAMPLE
	Webservice ws = Webservice.getInstance();
	ArrayList<Appointment> a = ws.GetAppointments("2012-11")
	****
	*/
	public ArrayList<Appointment> GetAppointments()
			throws ClientProtocolException, URISyntaxException, IOException,
			InvalidOAuthParametersError, InvalidOAuthTokenError,
			OAuthServiceFailureError, NotAllowedError, JSONException,
			SaveException, DestroyException {
		ArrayList<Appointment> array = new ArrayList<Appointment>();
		JSONObject appointment;
		JSONArray appointmentsList;
		Appointment s;
		JSONObject json = conectToServer("/api/appointments", "GET");
		if (statusSuccess(json)) {
			try {
				appointmentsList = json.getJSONArray("appointments");
			} catch (JSONException e1) {
				return array;
			}
			if (appointmentsList.length() == 0) {
				return array;
			}
			if (appointmentsList != null) {
				for (int i = 0; i < appointmentsList.length(); i++) {
					s = null;
					try {
						appointment = appointmentsList.getJSONObject(i);
					} catch (JSONException e) {
						Log.e("Egend.me-Exception",
								"Unknown Error on getting appointment");
						appointment = null;
					}
					if (appointment != null)
						s = createAppointment(appointment);
					if (s != null)
						array.add(s);
				}
			}
		} else {
			throwExceptionHandler(json);
		}
		return array;
	}
	
	/****f* Webservice/getResources
	* DESCRIPTION 
	* Método privado que constroi uma lista de recursos através de um JSON com essa informação.
	* INPUTS
	* Array json com informações de recursos
	* RESULT
	* Lista de objetos do tipo Resource. 
	* EXAMPLE
	****
	*/
	private ArrayList<Resource> getResources(JSONArray ResourcesList){
		ArrayList<Resource> resourceArray = new ArrayList<Resource>();
		JSONObject temp;
		Resource r;
		String name, desc;
		Integer capacity;
		Long id;
		
		if (ResourcesList.length()==0)
			return resourceArray;
		
		for (int i = 0; i < ResourcesList.length(); i++) {
			r =  null;
			capacity=null;
			id=null;
			name = desc = "";
			try {
				temp = ResourcesList.getJSONObject(i);
				id = getJsonLong(temp, "id");
				name = getJsonString(temp, "name");
				desc = getJsonString(temp, "description");
				capacity = getJsonInteger(temp, "capacity");
				
				r = new Resource(id, name, desc,capacity);
			} catch (JSONException e) {
				Log.e("Egend.me-Exception",
						"Unknown Error on ResourcesList");
				r = null;
			}
			if (r != null)
				resourceArray.add(r);
		}
		return resourceArray;
	}
	
	/****f* Webservice/getTasks
	* DESCRIPTION 
	* Método privado que constroi uma lista de tarefas através de um JSON com essa informação.
	* INPUTS
	* Array json com informações relativas a tarefas
	* RESULT
	* Lista de objetos do tipo Task. 
	* EXAMPLE
	****
	*/
	private ArrayList<Task> getTasks(JSONArray tasksList){
		ArrayList<Task> tasksArray = new ArrayList<Task>();
		Task t;
		JSONObject temp;
		String name, desc;
		Long id;
		Integer price, duration, max_people;
		
		if (tasksList.length()==0)
			return tasksArray;
		for (int i = 0; i < tasksList.length(); i++) {
			t = null;
			name = desc = "";
			price = duration = 0;
			try {
				temp = tasksList.getJSONObject(i);
				id = getJsonLong(temp, "id");
				name = getJsonString(temp, "name");
				desc = getJsonString(temp, "description");
				price = getJsonInteger(temp, "price");
				duration = getJsonInteger(temp, "duration");
				max_people  = getJsonInteger(temp, "max_people");
				
				t = new Task(id, name, desc, price, duration, max_people);
			} catch (JSONException e) {
				Log.e("Egend.me-Exception", "Unknown Error on Taskslist");
				t = null;
			}
			if (t != null)
				tasksArray.add(t);
		}
		return tasksArray;
	}
	
	/****f* Webservice/getClients
	* DESCRIPTION 
	* Método privado que constroi uma lista de clientes de um compromisso através de um JSON com essa informação.
	* INPUTS
	* Array json com informações de clientes
	* RESULT
	* Lista de objetos do tipo AppClient. 
	* EXAMPLE
	****
	*/
	private ArrayList<AppClient> getClients(JSONArray clientsList){
		ArrayList<AppClient> clientsArray = new ArrayList<AppClient>();
		JSONObject temp;
		String name, username;
//		String address,
		AppClient a;
		
		if (clientsList.length()==0)
			return clientsArray;
		for (int i = 0; i < clientsList.length(); i++) {
			a = null;
			temp = null;
			name = username = "";
			try {
				temp = clientsList.getJSONObject(i);
//				name = getJsonString(temp, "Name");
//				username = getJsonString(temp, "username");
//				address =  getJsonString(temp, "address");
//				a = new AppClient(name, address, username);
				//TODO: Versão alternativa
				name = getJsonString(temp, "email");
				username = getJsonString(temp, "username");
				a = new AppClient(name, "", username);
			} catch (JSONException e) {
				Log.e("Egend.me-Exception", "while getting client");
				a=null;
			}
			if (a != null)
				clientsArray.add(a);
		}
		return clientsArray;
	}

	/****f* Webservice/createAppointment
	* DESCRIPTION 
	* Método privado utilizado por outros métodos que durante a troca de informações com o webservice recebam informações de compromissos
	* INPUTS
	* Recebe um objeto JSONObject que tem informação de um compromisso
	* RESULT 
	* Retorna um novo objeto do tipo Appointment que representa o compromisso e tem a informação adquirida do objeto que representa o JSON.
	* EXAMPLE
	JSONObject  appointment = appointmentsList.getJSONObject(i);
	Appointment s = createAppointment(appointment);
	****
	*/
	private Appointment createAppointment(JSONObject app)
			throws MalformedURLException, IOException {
		String serice_id, service, serviceDescription, Comment;
		Long id, service_category_id;
		SimpleService s;
		JSONObject serviceJSON;
		Appointment appointment;
		GregorianCalendar beginDate = new GregorianCalendar();
		GregorianCalendar endDate = new GregorianCalendar();
		ArrayList<Resource> resourceArray = new ArrayList<Resource>();
		ArrayList<Task> tasksArray = new ArrayList<Task>();
		ArrayList<AppClient> clientsArray = new ArrayList<AppClient>();

		try {
			id = getJsonLong(app, "id"); 
			beginDate = getJsonDate(app, "begin");
			endDate = getJsonDate(app, "end");
			Comment = getJsonString(app, "comment");
			
			serviceJSON = app.getJSONObject("service");
			serice_id = getJsonString(serviceJSON, "id");
			service = getJsonString(serviceJSON, "name");
			serviceDescription = getJsonString(serviceJSON, "description");
			service_category_id = getJsonLong(serviceJSON, "category_id");
			s = new SimpleService(serice_id, service, serviceDescription, service_category_id);
		} catch (Exception e) {
			Log.e("Egend.me-createAppointmentException",
					"Exception while reading json: " + e.getMessage());
			return null;
		}
		

		// *************** ResourcesList
		try {
			JSONArray ResourcesList = app.getJSONArray("resources");
			resourceArray = getResources(ResourcesList);
		} catch (Exception e) {}

		// *************** TasksList
		try {
			JSONArray tasksList = app.getJSONArray("tasks");
			tasksArray = getTasks(tasksList);
		} catch (Exception e) {}

		// *************** ClientsList
		try {
			JSONArray clientsList = app.getJSONArray("end_users");
			clientsArray = getClients(clientsList);
		} catch (Exception e) {}

		appointment = new Appointment(id,s, beginDate, endDate, Comment,
				resourceArray, tasksArray, clientsArray);

		return appointment;
	}
	
	/****f* Webservice/createAgendaAppointment
	* DESCRIPTION 
	* Método privado utilizado para os compromissos do GetAgenda
	* INPUTS
	* Recebe um objeto JSONObject que tem informação de um compromisso
	* RESULT 
	* Retorna um novo objeto do tipo Appointment que representa o compromisso e tem a informação adquirida do objeto que representa o JSON.
	* EXAMPLE
	JSONObject  appointment = appointmentsList.getJSONObject(i);
	Appointment s = createAppointment(appointment);
	****
	*/
	private Appointment createAgendaAppointment(JSONObject app)
			throws MalformedURLException, IOException {
		String serice_id, service, serviceDescription, bDateTemp, eDateTemp, Comment;
		SimpleService s;
		Long id;
		Appointment appointment;
		GregorianCalendar beginDate = new GregorianCalendar();
		GregorianCalendar endDate = new GregorianCalendar();
		ArrayList<Resource> resourceArray = new ArrayList<Resource>();
		ArrayList<Task> tasksArray = new ArrayList<Task>();
		ArrayList<AppClient> clientsArray = new ArrayList<AppClient>();

		try {
			serice_id = getJsonString(app, "service_id");
			service = getJsonString(app, "service");
			serviceDescription = getJsonString(app, "serviceDescription");
			s = new SimpleService(serice_id, service, serviceDescription,null); // NULL: Categoria não definida na agenda.
			
			id=getJsonLong(app, "appointment_id");
			bDateTemp = app.getString("begin");
			eDateTemp = app.getString("end");
			Comment = getJsonString(app, "comment");
		} catch (Exception e) {
			Log.e("Egend.me-createAppointmentException",
					"Exception while reading json: " + e.getMessage());
			return null;
		}

		try {
			beginDate.setTime(this.formatter.parse(bDateTemp));
			endDate.setTime(this.formatter.parse(eDateTemp));
		} catch (Exception e) {
			Log.e("Egend.me-createAppointmentException",
					"Exception while reading dates probably: " + e.getMessage());
			return null;
		}

		// *************** ResourcesList
		try {
			JSONArray ResourcesList = app.getJSONArray("resources");
			resourceArray = getResources(ResourcesList);
		} catch (Exception e) {}

		// *************** TasksList
		try {
			JSONArray tasksList = app.getJSONArray("tasks");
			tasksArray = getTasks(tasksList);
		} catch (Exception e) {}

		// *************** ClientsList
		try {
			JSONArray clientsList = app.getJSONArray("clients");
			clientsArray = getClients(clientsList);
		} catch (Exception e) {}

		appointment = new Appointment(id,s, beginDate, endDate, Comment,
				resourceArray, tasksArray, clientsArray);

		return appointment;
	}

	/****f* Webservice/getDisponibilidade
	* DESCRIPTION 
	* Método que retorna um conjunto de dados que representam a disponibilidade diária do mês pedido de um serviço
	* INPUTS
	* Recebe um objeto que representa a data ao qual o conjunto deve começar e ainda o identificador do serviço.
	* RESULT 
	* É retornado um array que associa uma disponibilidade em percentagem (números inteiros) a um dia do mÊs.
	* EXAMPLE
	Webservice ws = Webservice.getInstance();
	Long id = 3312312331;
	ArrayList<Integer> disponibilidades = ws.getDisponibilidade(new GregorianCalendar(),id);
	****
	*/
	public ArrayList<Integer> getDisponibilidade(GregorianCalendar startMonth,
			Long ServiceId) throws ClientProtocolException, URISyntaxException,
			IOException, InvalidOAuthParametersError, InvalidOAuthTokenError,
			OAuthServiceFailureError, NotAllowedError, JSONException,
			SaveException, DestroyException {
		ArrayList<Integer> r = new ArrayList<Integer>();
		Integer disp;
		JSONArray disponibilidadesList;

		String year = String.valueOf(startMonth.get(GregorianCalendar.YEAR));
		String month = String.valueOf(startMonth.get(GregorianCalendar.MONTH));
		String parcialUrl = "/api/services/" + ServiceId.toString() 
						  + "/availability?month=" + month 
						  + "&year=" + year;

		JSONObject json = conectToServer(parcialUrl, "GET");
		if (statusSuccess(json)) {
			try {
				disponibilidadesList = json.getJSONObject("availability")
						.getJSONArray("days");
				if (disponibilidadesList != null) {
					if (disponibilidadesList.length() == 0) {
						return r;
					} else {
						for (int i = 1; i < disponibilidadesList.length(); i++) {
							try {
								disp = disponibilidadesList.getInt(i);
								r.add(disp);
							} catch (Exception e) {
								Log.e("Egend.me-Exception",
										"Error on parsing availabilities");
							}
						}
					}
				}
			} catch (JSONException e1) {
				return r;
			}
		} else {
			throwExceptionHandler(json);
		}

		return r;
	}
	
	/****f* Webservice/getDisponibilidade
	* DESCRIPTION 
	* Método que retorna um conjunto de dados que representam a disponibilidade diária do mês pedido de um serviço
	* INPUTS
	* Recebe um objeto que representa a data ao qual o conjunto deve começar e ainda o identificador do serviço.
	* RESULT 
	* É retornado um array que associa uma disponibilidade em percentagem (números inteiros) a um dia do mÊs.
	* EXAMPLE
	Webservice ws = Webservice.getInstance();
	Long id = 3312312331;
	ArrayList<Integer> disponibilidades = ws.getDisponibilidade(new GregorianCalendar(),id);
	****
	*/
	public HashMap<Date, Integer> getDisponibilidadeAnual(Integer year,
			Long ServiceId) throws ClientProtocolException, URISyntaxException,
			IOException, InvalidOAuthParametersError, InvalidOAuthTokenError,
			OAuthServiceFailureError, NotAllowedError, JSONException,
			SaveException, DestroyException {
		Date d;
		HashMap<Date, Integer> hash = new HashMap<Date, Integer>();
		JSONObject mesJson;
		Integer mes;
		JSONArray disponibilidadesList, dias;

		ArrayList<BasicNameValuePair> postParameters = new ArrayList<BasicNameValuePair>();
		postParameters.add(new BasicNameValuePair("Authorization", "OAuth "
				+ this.token));
		String parcialUrl = "/api/services/" + ServiceId.toString()
				+ "/year_availability?year=" + Integer.toString(year);

		JSONObject json = conectToServer(parcialUrl, "GET");
		if (statusSuccess(json)) {
			year = year - 1900;
			try {
				disponibilidadesList = json.getJSONArray("availabilities");
				if (disponibilidadesList != null) {
					if (disponibilidadesList.length() == 0) {
						return hash;
					} else {
						for (int i = 1; i < disponibilidadesList.length(); i++) {
							try {
								mesJson = disponibilidadesList.getJSONObject(i);
								mes = mesJson.getInt("month");
								dias = mesJson.getJSONArray("days");
								for (int j = 1; j < dias.length(); j++) {
									d = new Date(year, mes - 1, j);
									hash.put(d, new Integer(dias.getInt(j)));
								}
							} catch (Exception e) {
								Log.e("Egend.me-Exception",
										"Error on parsing availabilities");
							}
						}
					}
				}
			} catch (JSONException e1) {
				return hash;
			}
		} else {
			throwExceptionHandler(json);
		}

		return hash;
	}

	/****f* Webservice/delayWarning
	* DESCRIPTION 
	* Avisar que vai chegar uma quantidade de minutos atrasado a um determinado Appointment
	* INPUTS
	* Recebe o número de minutos e o Appointment a avisar
	* RESULT 
	* Retorna um booleano que representa o sucesso/insucesso da operação.
	****
	*/
	public Boolean delayWarning(Integer minutes, Long appID) throws ClientProtocolException, URISyntaxException, IOException, JSONException, InvalidOAuthParametersError, InvalidOAuthTokenError, OAuthServiceFailureError, NotAllowedError, SaveException, DestroyException {
		String parcialUrl = "/api/appointments/" + Long.toString(appID)
				+ "/delay_warning";

		ArrayList<BasicNameValuePair> postParameters = new ArrayList<BasicNameValuePair>();
		addParam(postParameters, "duracao", minutes);
		JSONObject json = conectToServer(parcialUrl, "POST", postParameters);
		if (statusSuccess(json))
			return true;
		throwExceptionHandler(json);
		return false;
	}

	/****f* Webservice/clickPartnerService
	* DESCRIPTION 
	* Adiciona mais uma view para os serviços patrocinados que são apresentados nas pesquisas
	* INPUTS
	* Recebe o ID do serviço
	* RESULT 
	* Retorna um booleano que representa o sucesso/insucesso da operação.
	****
	*/
	public Boolean clickPartnerService(Long service_ID) throws ClientProtocolException, URISyntaxException, IOException, JSONException, InvalidOAuthParametersError, InvalidOAuthTokenError, OAuthServiceFailureError, NotAllowedError, SaveException, DestroyException {
		ArrayList<BasicNameValuePair> postParameters = new ArrayList<BasicNameValuePair>();
		addParam(postParameters, "id", service_ID);
		JSONObject json = conectToServer("/api/services/click", "POST", postParameters);
		if (statusSuccess(json))
			return true;
		throwExceptionHandler(json);
		return false;
	}
	
	/****f* Webservice/notifyIfCancelAppointment
	* DESCRIPTION 
	* Pedir para avisar que que um compromisso foi cancelado
	* INPUTS
	* Recebe identificador do Appointment
	* RESULT 
	* Retorna um booleano que representa o sucesso/insucesso da operação.
	****
	*/
	public Boolean notifyIfCancelAppointment(Long appID) throws ClientProtocolException, URISyntaxException, IOException, JSONException, InvalidOAuthParametersError, InvalidOAuthTokenError, OAuthServiceFailureError, NotAllowedError, SaveException, DestroyException {
		String parcialUrl = "/api/appointments/" + Long.toString(appID)
				+ "/notify_when_available";
		JSONObject json = conectToServer(parcialUrl, "GET");
		if (statusSuccess(json))
			return true;
		throwExceptionHandler(json);
		return false;
	}

	/****f* Webservice/answerExchanges
	* DESCRIPTION 
	* Responder se aceita a permuta ou não
	* INPUTS
	* Recebe identificador da permuta e a resposta se True ou False
	* RESULT 
	* Retorna um booleano que representa o sucesso/insucesso da operação.
	****
	*/
	public Boolean answerExchanges(Long exchangeID, Boolean answer) throws ClientProtocolException, URISyntaxException, IOException, JSONException, InvalidOAuthParametersError, InvalidOAuthTokenError, OAuthServiceFailureError, NotAllowedError, SaveException, DestroyException {
		String parcialUrl = "/api/exchanges/" + Long.toString(exchangeID)
				+ "/answer";
		ArrayList<BasicNameValuePair> postParameters = new ArrayList<BasicNameValuePair>();
		addParam(postParameters, "response", answer);
		JSONObject json = conectToServer(parcialUrl, "PUT", postParameters);
		if (statusSuccess(json))
			return true;
		throwExceptionHandler(json);
		return false;
	}

	/****f* Webservice/addBookmark
	* DESCRIPTION 
	* Adiciona um favorito à conta de utilizador autenticada no servidor do egend.me.
	* INPUTS
	* Recebe o identificador do serviço a marcar como favorito.
	* RESULT 
	* Retorna um booleano que representa o sucesso/insucesso da operação.
	* EXAMPLE
	Webservice ws = Webservice.getInstance();
	if (ws.addBookmark(id))
		popUpSucess();
	else
		popUpInsucess();
	****
	*/
	public Boolean addBookmark(Long ServiceId) throws Exception {
		ArrayList<BasicNameValuePair> postParameters = new ArrayList<BasicNameValuePair>();
		postParameters.add(new BasicNameValuePair("service_id", Long
				.toString(ServiceId)));
		JSONObject json = conectToServer("/api/bookmarks", "POST",
				postParameters);

		if (statusSuccess(json))
			return true;
		throwExceptionHandler(json);
		return false;
	}
	
	/****f* Webservice/delBookmark
	* DESCRIPTION 
	* Remove o favorito pedido associado ao utilizador autenticado. 
	* INPUTS
	* Recebe o identificador do favorito.
	* RESULT 
	* Retorna um booleano que representa o sucesso/insucesso da operação.
	* EXAMPLE
	Webservice ws = Webservice.getInstance();
	if (ws.delBookmark(bookmark.getId()))
		popUpSucess();
	else
		popUpInsucess();
	 * @throws URISyntaxException 
	****
	*/
	public Boolean delBookmark(Long BookmarkId) throws ClientProtocolException,
			IOException, InvalidOAuthParametersError, InvalidOAuthTokenError,
			OAuthServiceFailureError, NotAllowedError, JSONException,
			SaveException, DestroyException, URISyntaxException {
		String parcialUrl = "/api/bookmarks/" + Long.toString(BookmarkId);
		
		JSONObject json = conectToServer(parcialUrl, "DELETE");
		if (statusSuccess(json))
			return true;
		throwExceptionHandler(json);
		return false;
	}
	
	
	/****f* Webservice/markAsRead
	* DESCRIPTION 
	* Marca uma notificação como lida
	* INPUTS
	* Recebe o identificador da Notificação.
	* RESULT 
	* Retorna um booleano que representa o sucesso/insucesso da operação.
	* EXAMPLE
	Webservice ws = Webservice.getInstance();
	if (ws.markAsRead(notification.getId()))
		popUpSucess();
	else
		popUpInsucess();
	****
	*/
	public Boolean markAsRead(Long notificationkId)
			throws ClientProtocolException, IOException,
			InvalidOAuthParametersError, InvalidOAuthTokenError,
			OAuthServiceFailureError, NotAllowedError, JSONException,
			SaveException, DestroyException, URISyntaxException {
		String parcialUrl = "/api/notifications/"
				+ Long.toString(notificationkId);
		JSONObject json = conectToServer(parcialUrl, "DELETE");
		if (statusSuccess(json))
			return true;
		throwExceptionHandler(json);
		return false;
	}
	
	/****f* Webservice/delBookmark
	* DESCRIPTION 
	* Remove o favorito pedido associado ao utilizador autenticado. 
	* INPUTS
	* Recebe um favorito.
	* RESULT 
	* Retorna um booleano que representa o sucesso/insucesso da operação.
	* EXAMPLE
	Webservice ws = Webservice.getInstance();
	if (ws.delBookmark(bookmark))
		popUpSucess();
	else
		popUpInsucess();
	****
	*/
	public Boolean delBookmark(Bookmark b) throws ClientProtocolException,
			IOException, InvalidOAuthParametersError, InvalidOAuthTokenError,
			OAuthServiceFailureError, NotAllowedError, JSONException,
			SaveException, DestroyException, URISyntaxException {
		Long BookmarkId = b.getBookmarkId();
		String parcialUrl = "/api/bookmarks/" + Long.toString(BookmarkId);

		JSONObject json = conectToServer(parcialUrl, "DELETE");
		if (statusSuccess(json))
			return true;
		throwExceptionHandler(json);
		return false;
	}
	
	/****f* Webservice/delBookmark
	* DESCRIPTION 
	* Remove o favorito pedido associado ao utilizador autenticado. 
	* INPUTS
	* Recebe o identificador do favorito.
	* RESULT 
	* Retorna um booleano que representa o sucesso/insucesso da operação.
	* EXAMPLE
	Webservice ws = Webservice.getInstance();
	if (ws.delBookmark(bookmark.getId()))
		popUpSucess();
	else
		popUpInsucess();
	****
	*/
	public Boolean delAppointment(Long AppointmentId)
			throws ClientProtocolException, IOException,
			InvalidOAuthParametersError, InvalidOAuthTokenError,
			OAuthServiceFailureError, NotAllowedError, JSONException,
			SaveException, DestroyException, URISyntaxException {
		String parcialUrl = "/api/appointments/" + Long.toString(AppointmentId);

		JSONObject json = conectToServer(parcialUrl, "DELETE");
		if (statusSuccess(json))
			return true;
		throwExceptionHandler(json);
		return false;
	}
	
	/****f* Webservice/addAppointment
	* DESCRIPTION 
	* Cria um novo compromisso
	* INPUTS
	* Recebe todos os campos possíveis de definição de compromisso
	* GregorianCalendar begin (data/hora de inicio): OBRIGATORIO;
	* String appointment_comment (comentário): OBRIGATORIO;
	* Boolean iParticipate (se o cliente actual participar no compromisso): OBRIGATORIO: TRUE se o utilizador participa; FALSE se não participa no Compromisso; 
	* GregorianCalendar notification_dateX (data/hora em que pretende receber o aviso de compromisso): FACULTATIVO: data para quando deve ser notificado;
	* Boolean recurrent (se for um appointment recorrente): FACULTATIVO: se for recurrente, precisa de estar a TRUE e os 3 cam
	* Integer delta (tempo em dias entre cada compromisso recorrente) Se for recurrente OBRIGATORIO;
	* Integer times (número de vezes que o compromisso recorrente se repete): Se for recurrente é OBRIGATORIO este ou o "until_dat"
	* GregorianCalendar until_dat (data/hora até que o compromisso se repete): Se for recurrente é OBRIGATORIO este ou o "times"
	* Long service_id (id do serviço) OBRIGATORIO
	* ArrayList<Resource> resources, OBRIGATORIO
	* ArrayList<Task> tasks, OBRIGATORIO
	* ArrayList<String> end_users_ids OBRIGATORIO
	* Boolean force_overlap (se confirmar que não se importa de sobrepor um ou mais (novos) compromissos, com algum compromisso seu ja existente) FACULTATIVO: utilizado quando, depois da exception enviada UserOverlappedAppointment e depois do utilizador aceitar continuar a enviar o appointment
	* Boolean force_valid_creation (se confirmar que apesar de alguns dos compromissos recorrentes não puderem ser criados, quer criar os válidos) FACULTATIVO: Utilizado quando, depois da exception enviada RecurrentAppointmentException e depois do utilizador aceitar continuar a enviar o appointment
	* RESULT 
	* Retorna um booleano que representa o sucesso/insucesso da operação. 
	****
	*/
	public Boolean addAppointment(GregorianCalendar begin,
			String appointment_comment, Boolean iParticipate,
			GregorianCalendar notification_dateX, Boolean recurrent,
			Integer delta, Integer times, GregorianCalendar until_date,
			Long service_id, ArrayList<Resource> resources,
			ArrayList<Task> tasks, ArrayList<String> end_users_ids,
			Boolean force_overlap, Boolean force_valid_creation)
			throws ClientProtocolException, IOException,
			InvalidOAuthParametersError, InvalidOAuthTokenError,
			OAuthServiceFailureError, NotAllowedError, JSONException,
			SaveException, DestroyException,
			userOverlappedAppointmentsException,
			RecurrentAppointmentsException, URISyntaxException {
		ArrayList<BasicNameValuePair> postParameters = new ArrayList<BasicNameValuePair>();

		addParam(postParameters, "begin", begin);
		addParam(postParameters, "comment", appointment_comment);
		addParam(postParameters, "service_id", service_id);

		if (iParticipate)
			addParam(postParameters, "i_participate_yes", iParticipate);
		else
			addParam(postParameters, "i_participate_no", iParticipate);

		if (notification_dateX != null)
			addParam(postParameters, "notification_dateX", notification_dateX);

		if (recurrent != null) {
			addParam(postParameters, "recurrent", recurrent);
			addParam(postParameters, "delta", delta);
			if (times != null)
				addParam(postParameters, "times", times);
			else
				addParam(postParameters, "until_date", until_date);
		}

		if (force_overlap != null)
			addParam(postParameters, "force_overlap", force_overlap);
		if (force_valid_creation != null)
			addParam(postParameters, "force_valid_creation",
					force_valid_creation);

		StringBuilder stringbuilder = new StringBuilder();
		for (Resource r : resources)
			stringbuilder.append(r.getStringId() + ",");
		stringbuilder.deleteCharAt(stringbuilder.length() - 1);
		addParam(postParameters, "resources_ids", stringbuilder.toString());

		stringbuilder = new StringBuilder();
		for (Task t : tasks)
			stringbuilder.append(t.getStringId() + ",");
		stringbuilder.deleteCharAt(stringbuilder.length() - 1);
		addParam(postParameters, "tasks_ids", stringbuilder.toString());

		stringbuilder = new StringBuilder();
		for (String s : end_users_ids)
			stringbuilder.append(s + ",");
		stringbuilder.deleteCharAt(stringbuilder.length() - 1);
		addParam(postParameters, "end_users_ids", stringbuilder.toString());
		
		JSONObject json = conectToServer("/api/appointments", "POST",
				postParameters);
		Log.d("paramters", postParameters.toString());
		if (statusSuccess(json))
			return true;
		else {
			Integer number = getJsonInteger(json, "status");
			if (number == null)
				throwExceptionHandler(json);
			if (number == 443)
				throw new userOverlappedAppointmentsException();
			else if (number == 444)
				throw new RecurrentAppointmentsException();
		}
		throwExceptionHandler(json);
		return false;
	}
	
	/****f* Webservice/getJsonString
	* DESCRIPTION 
	* Método privado para obter uma string de um objeto Json.
	* INPUTS
	* Objeto Json simples que representa uma string.
	* RESULT 
	* String em caso de sucesso na leitura;
	* No caso de insucesso retorna null e apresenta uma linha no Log.D.
	* EXAMPLE
	name = getJsonString(profile, "name");
	****
	*/
	protected String getJsonString(JSONObject o, String name){
		try{
			String temp = o.getString(name);
			if (temp.equals("null"))
				return "";
			return temp;
		}catch (Exception e) {
			Log.d("JSON-parsing(String)", "Campo: '" + name + "' mensagem: " + e.getMessage());
			return "";
		}
	}
	
	/****f* Webservice/getJsonLong
	* DESCRIPTION 
	* Método privado para obter um long de um objeto Json.
	* INPUTS
	* Objeto Json simples que representa um long.
	* RESULT 
	* Long em caso de sucesso na leitura;
	* No caso de insucesso retorna null e apresenta uma linha no Log.D.
	* EXAMPLE
	Long id = getJsonLong(profile.getJSONObject("user"), "id");
	****
	*/
	protected Long getJsonLong(JSONObject o, String name){
		try{
			return o.getLong(name);
		}catch (Exception e) {
			Log.d("JSON-parsing(Long)", "Campo: '" + name + "' mensagem: " + e.getMessage());
			return null;
		}
	}
	
	/****f* Webservice/getJsonInteger
	* DESCRIPTION 
	* Método privado para obter um inteiro de um objeto Json.
	* INPUTS
	* Objeto Json simples que representa um inteiro.
	* RESULT 
	* Inteiro em caso de sucesso na leitura;
	* No caso de insucesso retorna null e apresenta uma linha no Log.D.
	* EXAMPLE
	Integer rating = getJsonInteger(service, "rating");
	****
	*/
	protected Integer getJsonInteger(JSONObject o, String name){
		try{
			return o.getInt(name);
		}catch (Exception e) {
			Log.d("JSON-parsing(Integer)", "Campo: '" + name + "' mensagem: " + e.getMessage());
			return null;
		}
	}
	
	/****f* Webservice/getJsonDate
	* DESCRIPTION 
	* Método privado para obter uma data de um objeto Json.
	* INPUTS
	* Objeto Json simples que representa uma data.
	* RESULT 
	* GregorianCalendar em caso de sucesso na leitura;
	* No caso de insucesso retorna null e apresenta uma linha no Log.D.
	* EXAMPLE
	GregorianCalendar beginDate = getJsonDate(slot, "beginDate");
	****
	*/
	protected GregorianCalendar getJsonDate(JSONObject o, String name){
		GregorianCalendar begDate = new GregorianCalendar();
		String beginDate;

		try{
			beginDate = o.getString(name);
			begDate.setTime(this.formatter.parse(beginDate));
			return begDate;
		}catch (Exception e) {
			Log.d("JSON-parsing(Datas)", "Campo: '" + name + "' mensagem: " + e.getMessage());
			return null;
		}
	}
	
	/****f* Webservice/statusSuccess
	* DESCRIPTION 
	* Método para saber se a operação decorreu com sucesso ou não.
	* O sebservice envia sempre um objeto a relatar o estado de sucesso ou não das operações. Assim este método lê o estado da operação.
	* INPUTS
	* O json retornado pelo pedido do webservice.
	* RESULT 
	* Verdadeiro em caso de operação bem sucessedida.
	* False em caso de falha na operação.
	* EXAMPLE
		if (statusSuccess(json)) {
			continue();
		} else {
			throwExceptionHandler(json);
		}
	****
	*/
	protected Boolean statusSuccess(JSONObject o){
		try{
			if (o.getString("status").equals("success"))
				return true;
		}catch (Exception e) {
			return false;
		}
		return false;
	}
	
	
	// material para tratar os parâmetros enviados:
	protected void addParam(ArrayList<BasicNameValuePair> postParameters,String field, String value){
		postParameters.add(new BasicNameValuePair(field, value));
	}
	
	protected void addParam(ArrayList<BasicNameValuePair> postParameters,String field, Long value){
		postParameters.add(new BasicNameValuePair(field, Long.toString(value)));
	}
	
	protected void addParam(ArrayList<BasicNameValuePair> postParameters,String field, Integer value){
		postParameters.add(new BasicNameValuePair(field, Integer.toString(value)));
	}
	
	protected void addParam(ArrayList<BasicNameValuePair> postParameters,String field, GregorianCalendar value){
		String s = this.formatter.format(value.getTime());
		postParameters.add(new BasicNameValuePair(field, s));
	}
	
	protected void addParam(ArrayList<BasicNameValuePair> postParameters,String field, Boolean value){
		if (value)
			postParameters.add(new BasicNameValuePair(field, "True"));
		else
			postParameters.add(new BasicNameValuePair(field, "False"));
	}

	public static String getDomain() {
		return domain;
	}

	public static String getOauth_consumer_key() {
		return oauth_consumer_key;
	}


	public static String getOauth_consumer_secret() {
		return oauth_consumer_secret;
	}

	public String createUrl(String s){
		Log.d("WebService-URL", getDomain() + s);
		return getDomain() + s;
	}
	
	public JSONObject conectToServer(String parcialUrl,String action) throws ClientProtocolException, URISyntaxException, IOException, JSONException{
		ArrayList<BasicNameValuePair> postParameters = new ArrayList<BasicNameValuePair>();
		postParameters.add(new BasicNameValuePair("Authorization", "OAuth "
				+ this.token));
		return conectToServer(parcialUrl,action,postParameters);
	}
	
	public JSONObject conectToServer(String parcialUrl,String action,ArrayList<BasicNameValuePair> postParameters) throws ClientProtocolException, URISyntaxException, IOException, JSONException{		
		String jsonString="";
		
		String url = getDomain() + parcialUrl; 
		Log.d("WebService:URL",action + " " + url);
		
		if (action.equals("GET"))
			jsonString = Http.executeHttpGet(url, postParameters);
		else if (action.equals("POST"))
			jsonString = Http.executeHttpPost(url, postParameters, this.token);
		else if (action.equals("PUT"))
			jsonString = Http.executeHttpPut(url, postParameters, this.token);
		else if (action.equals("DELETE"))
			jsonString = Http.executeHttpDelete(url, this.token);
		
		Log.d("WebService:JsonString", jsonString);
		return new JSONObject(jsonString);
	}
}
